using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using NAudio.Wave;

namespace NAudio.Mixer
{
    /// <summary>Represents a Windows mixer device</summary>
    public class Mixer 
    {
        private MixerInterop.MIXERCAPS caps;
        private IntPtr mixerHandle;
        private MixerFlags mixerHandleType;
        
        /// <summary>The number of mixer devices available</summary>    
        public static int NumberOfDevices 
        {
            get 
            {
                return MixerInterop.mixerGetNumDevs();
            }
        }
        
        /// <summary>Connects to the specified mixer</summary>
        /// <param name="mixerIndex">The index of the mixer to use. 
        /// This should be between zero and NumberOfDevices - 1</param>
        public Mixer(int mixerIndex) 
        {
            if(mixerIndex < 0 || mixerIndex >= NumberOfDevices) 
            {
                throw new ArgumentOutOfRangeException("mixerID");
            }
            caps = new MixerInterop.MIXERCAPS();
            MmException.Try(MixerInterop.mixerGetDevCaps((IntPtr)mixerIndex,ref caps,Marshal.SizeOf(caps)),"mixerGetDevCaps");
            this.mixerHandle = (IntPtr)mixerIndex;
            this.mixerHandleType = MixerFlags.Mixer;
            
            // TODO: optionally support really opening the mixer device
            //MmException.Try(MixerInterop.mixerOpen(out mixerHandle, mixerIndex, IntPtr.Zero, IntPtr.Zero, 0), "mixerOpen");
        }

        /// <summary>The number of destinations this mixer supports</summary>
        public int DestinationCount 
        {
            get 
            {
                return (int) caps.cDestinations;
            }
        }
        
        /// <summary>The name of this mixer device</summary>
        public String Name 
        {
            get 
            {
                return caps.szPname;
            }
        }
        
        /// <summary>The manufacturer code for this mixer device</summary>
        public Manufacturers Manufacturer 
        {
            get 
            {
                return (Manufacturers) caps.wMid;
            }
        }

        /// <summary>The product identifier code for this mixer device</summary>
        public int ProductID 
        {
            get 
            {
                return caps.wPid;
            }
        }
        
        /// <summary>Retrieve the specified MixerDestination object</summary>
        /// <param name="destinationIndex">The ID of the destination to use.
        /// Should be between 0 and DestinationCount - 1</param>
        public MixerLine GetDestination(int destinationIndex) 
        {
            if(destinationIndex < 0 || destinationIndex >= DestinationCount) 
            {
                throw new ArgumentOutOfRangeException("destinationIndex");
            }
            return new MixerLine(mixerHandle, destinationIndex, mixerHandleType);
        }

        /// <summary>
        /// A way to enumerate the destinations
        /// </summary>
        public IEnumerable<MixerLine> Destinations
        {
            get
            {
                for (int destination = 0; destination < DestinationCount; destination++)
                {
                    yield return GetDestination(destination);
                }
            }
        }

        /// <summary>
        /// A way to enumerate all available devices
        /// </summary>
        public static IEnumerable<Mixer> Mixers
        {
            get
            {
                for (int device = 0; device < Mixer.NumberOfDevices; device++)
                {
                    yield return new Mixer(device);
                }
            }
        }
    }
}
